package com.hx.zhg.web.controller;

import com.hx.zhg.constant.CommonConstant;
import com.hx.zhg.constant.ErrorCodeEnum;
import com.hx.zhg.exception.BusinessException;
import com.hx.zhg.util.JsonUtils;
import com.hx.zhg.web.baseobj.ResultData;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.ui.ModelMap;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.ServletRequestDataBinder;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.ValidationException;
import javax.validation.Validator;
import java.io.IOException;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

@ControllerAdvice
public class BaseController {

    private static final Logger log = LoggerFactory.getLogger(BaseController.class);

    private static final String SUCCESS_FLAG = "success";

    private static final String ERROR_404 = "/error/404";

    private static final String ERROR_400 = "/error/400";

    @Value("${server.context-path}")
    protected String contextPath;

    @ModelAttribute
    public void addAttributes(ModelMap modelMap) {
        modelMap.addAttribute("contextPath", contextPath);
    }

    @InitBinder
    public void initBind(ServletRequestDataBinder binder) {
        binder.registerCustomEditor(String.class, null);
    }

    /**
     * 从header中查询timeZoneId
     *
     * @param request
     * @return
     */
    protected String getTimeZoneId(HttpServletRequest request) {
        //获取timeZoneId
        return request.getHeader(CommonConstant.HEADER_TIMEZONE);
    }

    protected String getSessionToken(HttpServletRequest request) {
        //获取sessionToken
        return request.getHeader(CommonConstant.HEADER_APP_SESSION);
    }

    /**
     * 获取所有header,返回JSON格式
     *
     * @return
     */
    protected String getHeaders(HttpServletRequest request) {
        String header = "";
        Enumeration<String> headerNames = request.getHeaderNames();
        if (headerNames != null) {
            Map<String, String> headersMap = new HashMap<>();
            while (headerNames.hasMoreElements()) {
                String headerName = headerNames.nextElement();
                String headerVal = request.getHeader(headerName);
                headersMap.put(headerName, headerVal);
            }
            header = JsonUtils.objToJson(headersMap);
        }
        return header;
    }

    /**
     * 查询用户id
     *
     * @param request
     * @return
     */
    protected Integer getUserId(HttpServletRequest request) {
        String userIdStr = request.getHeader(CommonConstant.HEADER_USERID);
        Integer userId = null;
        if (StringUtils.isNotBlank(userIdStr) && NumberUtils.isDigits(userIdStr)) {
            userId = Integer.parseInt(userIdStr);
        }
        return userId;
    }


    protected String getUserAgent(HttpServletRequest request) {
        return request.getHeader(CommonConstant.HEADER_USER_AGENT);
    }


    /**
     * 返回成功，没有数据
     *
     * @throws Exception
     */
    protected String retSuccessNoData() {
        return assembleInfo(ErrorCodeEnum.SUCCESS.getRetCode(), ErrorCodeEnum.SUCCESS.getRetMsg(), null);
    }

    /**
     * 返回成功，没有数据
     *
     * @throws Exception
     */
    protected String retSuccessNoData(String statusInfo) {
        return assembleInfo(ErrorCodeEnum.SUCCESS.getRetCode(), statusInfo, null);
    }

    /**
     * 返回成功，带成功标记
     *
     * @throws Exception
     */
    protected String retSuccessWithFlag() {
        return assembleInfo(ErrorCodeEnum.SUCCESS.getRetCode(), ErrorCodeEnum.SUCCESS.getRetMsg(), SUCCESS_FLAG);
    }

    /**
     * 写入成功的返回数据
     *
     * @throws Exception
     */
    protected String retSuccess(Object data) {
        return assembleInfo(ErrorCodeEnum.SUCCESS.getRetCode(), ErrorCodeEnum.SUCCESS.getRetMsg(), data);
    }

    /**
     * 写入成功的返回数据
     *
     * @param statusInfo
     * @throws Exception
     */
    protected String retSuccess(String statusInfo, Object data) {
        return assembleInfo(ErrorCodeEnum.SUCCESS.getRetCode(), statusInfo, data);
    }

    /**
     * 写入失败的返回数据
     *
     * @param errorCode
     * @param msgKey
     * @throws Exception
     */
    protected String retError(Integer errorCode, String msgKey, Object data) throws Exception {
        return assembleInfo(errorCode, msgKey, data);
    }

    /**
     * 未绑定手机号
     *
     * @throws Exception
     */
    protected String retNotBuildMobilePhone() {
        return assembleInfo(ErrorCodeEnum.REAL_NAME_DIALOG.getRetCode(), ErrorCodeEnum.REAL_NAME_DIALOG.getRetMsg(), null);
    }

    /**
     * 返回默认的参数错误的返回数据
     *
     * @throws Exception
     */
    protected String retParamErrorDefault() {
        return assembleInfo(ErrorCodeEnum.PARAM_ERROR.getRetCode(), ErrorCodeEnum.PARAM_ERROR.getRetMsg(), null);
    }


    /**
     * 返回参数错误的返回数据
     *
     * @param statusInfo
     * @throws Exception
     */
    protected String retParamError(String statusInfo) {
        return assembleInfo(ErrorCodeEnum.PARAM_ERROR.getRetCode(), statusInfo, null);
    }

    /**
     * 返回默认系统内部错误的返回数据
     *
     * @throws Exception
     */
    protected String retInternalErrorDefault() {
        return assembleInfo(ErrorCodeEnum.SYS_ERROR.getRetCode(), ErrorCodeEnum.SYS_ERROR.getRetMsg(), null);
    }

    /**
     * 返回系统错误的返回数据
     *
     * @param statusInfo
     * @throws Exception
     */
    protected String retInternalError(String statusInfo) {
        return assembleInfo(ErrorCodeEnum.SYS_ERROR.getRetCode(), statusInfo, null);
    }

    /**
     * 返回鉴权不通过的返回数据
     *
     * @throws Exception
     */
    protected String retAuthErrorDefault() {
        return assembleInfo(ErrorCodeEnum.AUTH_ERROR.getRetCode(), ErrorCodeEnum.AUTH_ERROR.getRetMsg(), null);
    }

    protected String retShowDialogDefault() {
        return assembleInfo(ErrorCodeEnum.SHOW_DIALOG.getRetCode(), ErrorCodeEnum.SHOW_DIALOG.getRetMsg(), null);
    }

    protected String retShowDialogMessage(String message) {
        int retCode = ErrorCodeEnum.SHOW_DIALOG.getRetCode();
        return assembleInfo(retCode, message, null);
    }

    /**
     * 返回鉴权不通过的返回数据
     *
     * @param statusInfo
     * @throws Exception
     */
    protected String retAuthError(String statusInfo) {
        return assembleInfo(ErrorCodeEnum.AUTH_ERROR.getRetCode(), statusInfo, null);
    }


    /**
     * request Token错误返回数据
     *
     * @return
     */
    protected String retRequestTokenErrorDefault() {
        return assembleInfo(ErrorCodeEnum.REQUEST_TOKEN_ERROR.getRetCode(), ErrorCodeEnum.REQUEST_TOKEN_ERROR.getRetMsg(), null);
    }

    /**
     * request Token 错误
     *
     * @param statusInfo
     * @return
     */
    protected String retRequestTokenError(String statusInfo) {
        return assembleInfo(ErrorCodeEnum.REQUEST_TOKEN_ERROR.getRetCode(), statusInfo, null);
    }

    /**
     * 返回返回值错误的的返回数据
     *
     * @throws Exception
     */
    protected String retResultErrorDefault() {
        return assembleInfo(ErrorCodeEnum.RESULT_ERROR.getRetCode(), ErrorCodeEnum.RESULT_ERROR.getRetMsg(), null);
    }

    /**
     * 返回返回值错误的的返回数据
     *
     * @param statusInfo
     * @throws Exception
     */
    protected String retResultError(String statusInfo) throws Exception {
        return assembleInfo(ErrorCodeEnum.RESULT_ERROR.getRetCode(), statusInfo, null);
    }

    /**
     * 返回返回值错误的的返回数据
     *
     * @throws Exception
     */
    protected String retInvalidRequestErrorDefault() {
        return assembleInfo(ErrorCodeEnum.INVALID_REQUEST.getRetCode(), ErrorCodeEnum.INVALID_REQUEST.getRetMsg(), null);
    }

    /**
     * 返回返回值错误的的返回数据
     *
     * @param statusInfo
     * @throws Exception
     */
    protected String retInvalidRequestError(String statusInfo) throws Exception {
        return assembleInfo(ErrorCodeEnum.INVALID_REQUEST.getRetCode(), statusInfo, null);
    }

    // 封装结果，并写入客户端response
    private String assembleInfo(Integer status, String statusInfo, Object data) {
        if (status == null) {
            log.error("response写入数据时状态未设置！");
            throw new BusinessException(
                    "response写入数据时状态未设置", String.valueOf(ErrorCodeEnum.RESULT_ERROR.getRetCode()));
        }
        if (statusInfo == null) {
            statusInfo = "";
        }
        if (data == null) {
            data = new Object();
        }
        ResultData resultData = new ResultData();
        resultData.setStatus(status);
        resultData.setData(data);
        resultData.setStatusInfo(statusInfo);
        // 写入数据到response
        String jsonResultData = JsonUtils.objToJson(resultData);
        return jsonResultData;
    }

    /**
     * 组装重定向url
     *
     * @param url
     * @return
     */
    protected String retRedirectUrl(String url) {
        return CommonConstant.REDIRECT_PREFIX + url;
    }

    /**
     * 返回404页面
     *
     * @param response
     * @return
     */
    protected String ERROR_404(HttpServletResponse response) {
        response.setStatus(HttpServletResponse.SC_NOT_FOUND);
        return ERROR_404;
    }

    /**
     * 返回400页面
     *
     * @param response
     * @return
     */
    protected String ERROR_400(HttpServletResponse response) {
        response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
        return ERROR_400;
    }

    /**
     * 校验参数
     *
     * @param bindingResult
     * @param response
     * @throws IOException
     */
    protected void validData(BindingResult bindingResult, HttpServletResponse response) throws IOException {
        if (bindingResult.hasErrors()) {
            StringBuffer sb = new StringBuffer();
            for (ObjectError error : bindingResult.getAllErrors()) {
                sb.append(error.getDefaultMessage());
            }
            ServletOutputStream out = response.getOutputStream();
            out.write(assembleInfo(ErrorCodeEnum.PARAM_ERROR.getRetCode(), sb.toString(), null).getBytes());
            out.flush();
            out.close();
        }
    }
}
